class DrawFanShape {
  constructor(viewer, sourceName, config) {
    this._viewer = viewer;
    let dataSourceList = viewer.dataSources.getByName(sourceName);
    if (!dataSourceList || dataSourceList.length === 0) {
      this._dataSource = new Cesium.CustomDataSource(sourceName);
      viewer.dataSources.add(this._dataSource); // 为扇形数据建立一个自定义数据源
    } else {
      this._dataSource = dataSourceList[0];
    }
    this._config = config || {
      color: Cesium.Color.RED,
      labelFont: "14px sans-serif",
      labelFillColor: Cesium.Color.BLACK,
      labelOutlineWidth: 1,
      labelOutlineColor: Cesium.Color.GOLD,
    };
  }
  /**
   * @description 画扇形（从正北开始顺时针旋转）
   * @param {String} id 扇形ID
   * @param {Object} position 中心点位置
   * @param {Object} heading 航向
   * @param {Object} color 扇形颜色
   * @param {Number} radius 扇形半径
   * @param {Number} angle 角度大小
   * @param {String} type 类别-用于区分是否是同一个目标的扇形
   */
  drawSector(params) {
    // 通过圆心（经纬度）、航偏角度d1、d2（d1<d2）、半径
    // d1、d2 可以通过此方法获取：假设当前目标航向角度A，d1 = A - 自定义扇形角度/2；d2 = A + 自定义扇形角度/2；
    let { id, position, heading, angle, color, type, radius, label } = params;
    let A = Cesium.Math.toDegrees(heading); // 弧度转角度
    let d1 = A - angle / 2; // 扇形第一个边的角度
    let d2 = A + angle / 2; // 扇形第二个边的角度
    let pos = this.cartesian2Degrees(position);
    let { lon, lat, height } = pos;

    let box = this._dataSource.entities.add({
      id: id,
      polygon: {
        show: true,
        hierarchy: this.generateHierarchy(lon, lat, height, d1, d2, radius),
        material: color
          ? color.withAlpha(0.5)
          : this._config.color.withAlpha(0.5),
        outline: true,
        outlineWidth: 1,
        outlineColor: color ? color : this._config.color,
        zIndex: Math.floor(1000 / radius),
      },
      position: this.getLabelPos(lon, lat, height, A, radius), // Label显示需要位置
      label: {
        show: true,
        text: label,
        font: this._config.labelFont,
        fillColor: this._config.labelFillColor,
        outlineWidth: this._config.labelOutlineWidth,
        outlineColor: this._config.labelOutlineColor,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        pixelOffset: new Cesium.Cartesian2(0, 10),
        disableDepthTestDistance: 5e8,
        distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 6e6),
        horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
      },
      type: type,
      customFields: {
        // 缓存一些字段方便查找
        position: position,
        heading: heading,
        color: color,
        angle: angle,
        radius: radius,
      },
    });
    return box;
  }
  /**
   * 生成label的position
   */
  getLabelPos(lon, lat, height, A, radius) {
    let point = this.getPointByProjection(
      lon,
      lat,
      height,
      (90 - A) * (Math.PI / 180),
      radius * 1000
    );
    let cartesian = Cesium.Cartesian3.fromDegrees(
      Number(point[0]),
      Number(point[1]),
      height
    );
    return cartesian;
  }
  /**
   * 生成polygon线性环
   */
  generateHierarchy(lon, lat, height, d1, d2, radius) {
    let list = [Number(lon), Number(lat), Number(height)];
    //获取 航偏角d1 至 航偏角d2 弧段的点位信息
    for (let i = d1; i < d2; i += 1) {
      let point = this.getPointByProjection(
        lon,
        lat,
        height,
        (90 - i) * (Math.PI / 180),
        radius * 1000
      );
      list.push(Number(point[0]));
      list.push(Number(point[1]));
      list.push(height);
    }
    list.push(Number(lon));
    list.push(Number(lat));
    list.push(Number(height));
    return Cesium.Cartesian3.fromDegreesArrayHeights(list);
  }
  /**
   * @description 根据位置，方位，距离求经纬度
   * @param {int} lon 中心点经度
   * @param {*} lat 中心点纬度
   * @param {*} height 中心点高度
   * @param {*} direction 方向
   * @param {*} radius 半径
   */
  getPointByProjection(lon, lat, height, direction, radius) {
    // 观察点
    let cartesian = Cesium.Cartesian3.fromDegrees(lon, lat, height);
    // 世界坐标转为投影坐标
    let webMercatorProjection = new Cesium.WebMercatorProjection(
      this._viewer.scene.globe.ellipsoid
    );
    let viewPointWebMercator = webMercatorProjection.project(
      Cesium.Cartographic.fromCartesian(cartesian)
    );
    // 计算目标点
    let toPoint = new Cesium.Cartesian3(
      viewPointWebMercator.x + radius * Math.cos(direction),
      viewPointWebMercator.y + radius * Math.sin(direction),
      height
    );
    // 投影坐标转为世界坐标
    let cartographic = webMercatorProjection.unproject(toPoint);
    let point = [
      Cesium.Math.toDegrees(cartographic.longitude),
      Cesium.Math.toDegrees(cartographic.latitude),
    ];
    return point;
  }
  /**
   * @description 更新扇形
   * @param {String} id 扇形ID
   * @param {Object} position 中心点位置
   * @param {Object} color 扇形颜色
   * @param {Number} radius 扇形半径
   * @param {Number} angle 扇形角度大小
   */
  updateSector(params) {
    let { id, color, radius, angle } = params;
    let entity = this.getEntityById(id);
    if (entity) {
      if (color) {
        entity.polygon.material = color.withAlpha(0.5);
        entity.polygon.outlineColor = color;
        entity.customFields.color = color;
      }
      if (radius) {
        let customFields = this.getCustomFields(id);
        let pos = this.cartesian2Degrees(customFields.position);
        let lon = pos.lon;
        let lat = pos.lat;
        let height = pos.height;
        let A = Cesium.Math.toDegrees(customFields.heading); // 弧度转角度
        let d1 = A - customFields.angle / 2;
        let d2 = A + customFields.angle / 2;
        entity.polygon.hierarchy = this.generateHierarchy(
          lon,
          lat,
          height,
          d1,
          d2,
          radius
        );
        entity.customFields.radius = radius;
        entity.position = this.getLabelPos(lon, lat, height, A, radius);
      }
      if (angle) {
        let customFields = this.getCustomFields(id);
        let pos = this.cartesian2Degrees(customFields.position);
        let lon = pos.lon;
        let lat = pos.lat;
        let height = pos.height;
        let A = Cesium.Math.toDegrees(customFields.heading); // 弧度转角度
        let d1 = A - angle / 2;
        let d2 = A + angle / 2;
        entity.polygon.hierarchy = this.generateHierarchy(
          lon,
          lat,
          height,
          d1,
          d2,
          customFields.radius
        );
        entity.customFields.angle = angle;
      }
    }
  }
  // 外部接口 - 动态更新扇形位置（随目标运动）【不改变颜色、半径、角度大小】
  dynamicUpdate(id) {
    const change = (entity) => {
      let pos = this.cartesian2Degrees(entity.customFields.position.getValue());
      let A = Cesium.Math.toDegrees(entity.customFields.heading.getValue()); // 弧度转角度
      if (pos && A) {
        let lon = pos.lon;
        let lat = pos.lat;
        let height = pos.height;
        let d1 = A - entity.customFields.angle / 2;
        let d2 = A + entity.customFields.angle / 2;
        entity.polygon.hierarchy = this.generateHierarchy(
          lon,
          lat,
          height,
          d1,
          d2,
          entity.customFields.radius
        );
        entity.position = this.getLabelPos(
          lon,
          lat,
          height,
          A,
          entity.customFields.radius
        );
      } else {
        this._dataSource.entities.remove(entity);
      }
    };
    if (id) {
      let entity = this.getEntityById(id);
      change(entity);
    } else {
      let entities = this.getAllEntities();
      entities.forEach((entity) => {
        change(entity);
      });
    }
  }
  getEntityById(id) {
    return this._dataSource.entities.getById(id);
  }
  getEntitiesByType(type) {
    return this._dataSource.entities.values.filter(
      (entity) => entity.type === type
    );
  }
  getAllEntities() {
    return this._dataSource.entities.values;
  }
  getLength() {
    if (this._dataSource.entities.values) {
      return this._dataSource.entities.values.length;
    } else {
      return 0;
    }
  }
  getCustomFields(id) {
    let entity = this.getEntityById(id);
    if (entity) {
      return entity.customFields;
    } else {
      return {};
    }
  }
  clearById(id) {
    this._dataSource.entities.removeById(id);
  }
  clearByType(type) {
    let entities = this.getEntitiesByType(type);
    entities.forEach((entity) => {
      this._dataSource.entities.remove(entity);
    });
  }
  clearAll() {
    this._dataSource.entities.removeAll();
  }
  // 笛卡尔坐标转经纬度
  cartesian2Degrees(cartesian) {
    if (cartesian) {
      let cartographic =
        this._viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
      let pos = {
        lon: Cesium.Math.toDegrees(cartographic.longitude), // 经纬度
        lat: Cesium.Math.toDegrees(cartographic.latitude),
        height: cartographic.height,
      };
      return pos;
    } else {
      return cartesian;
    }
  }
}
export default DrawFanShape;
